﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Net;
using TCPIPControl.StructHelper;
using TCPIPControl;

namespace TcpLabCommon
{
    /// <summary>
    /// 网络封包服务类[提供封包的发送和读取]
    /// </summary>
    public abstract class Cls_NetPacketService
    {
        /// <summary>
        /// Tcp传输调用该构造方法
        /// </summary>
        /// <param name="netStream"></param>
        public Cls_NetPacketService(NetworkStream netStream)
        {
            this._netStream = netStream;
            this._protocolType = System.Net.Sockets.ProtocolType.Tcp;
        }

        /// <summary>
        /// Tcp传输调用该构造方法
        /// </summary>
        /// <param name="netStream"></param>
        public Cls_NetPacketService(Socket tcpSocket)
        {
            this._tcpSocket = tcpSocket;
            this._netStream = new NetworkStream(this._tcpSocket);
            this._protocolType = System.Net.Sockets.ProtocolType.Tcp;
        }

        /// <summary>
        /// Udp传输调用该构造方法
        /// </summary>
        /// <param name="udpSocket">Udp套接字</param>
        /// <param name="udpRemoteEndPoint">Udp发送的目标端点</param>
        public Cls_NetPacketService(Socket udpSocket, EndPoint udpRemoteEndPoint)
        {
            this._udpSocket = udpSocket;
            this._udpRemoteEndPoint = udpRemoteEndPoint;
            this._protocolType = System.Net.Sockets.ProtocolType.Udp;
        }

        /// <summary>
        /// 从网络文件数据中取出文件信息
        /// </summary>
        /// <param name="netFilebuffer">传送的文件，其内容=文件名长度(4字节)+文件名+文件内容</param>
        /// <returns>包含文件名称和文件内容的对象</returns>
        public NetFile ParseFile(Byte[] netFilebuffer)
        {
            if (netFilebuffer == null || netFilebuffer.Length == 0)
                return null;
            NetFile f = new NetFile();
            int filenamelen = BitConverter.ToInt32(netFilebuffer, 0);//文件名长度
            f.FileName = Encoding.Default.GetString(netFilebuffer, sizeof(Int32), filenamelen);
            f.Content = new Byte[netFilebuffer.Length - sizeof(Int32) - filenamelen];
            Array.Copy(netFilebuffer, sizeof(Int32) + filenamelen, f.Content, 0, f.Content.Length);

            return f;
        }

        /// <summary>
        /// 提取一个完整网络包然后返回[Tcp收包和Udp收包的行为不同,故转到子类实现]
        ///     如果收到的包是STRING类型,NetPacket.Data是发送的字符串
        ///     如果收到的包是BINARY类型,NetPacket.Data是发送的文件名长度+文件名+文件内容,请调用ParseFile函数进行解析
        ///     如果收到的包是COMPLEX类型,NetPacket.Data是发序列化的对象，可以直接转型使用
        /// </summary>
        /// <returns></returns>
        public abstract NetPacket ReceivePacket();

        /// <summary>
        /// 发送文本
        /// </summary>
        /// <param name="content"></param>
        public void SendText(string content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    PType = PacketType.STRING
                }
            };
            SendPacket(packet);
        }

        public void SendACQParametersConfig(TCPIPControl.StructHelper.ACQParametersConfig content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    PType = PacketType.ACQParametersConfig
                }
            };
            SendPacket(packet);
        }

        public void SendChannelConfig(ChannelConfig content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    //PType = PacketType.ChannelConfig
                }
            };
            SendPacket(packet);
        }



        public void SendTestPointConfig(TestPointConfig content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    //PType = PacketType.TestPointConfig
                }
            };
            SendPacket(packet);
        }



        public void SendSpeedConfig(SpeedConfig content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    //PType = PacketType.SpeedConfig
                }
            };
            SendPacket(packet);
        }

        public void SendDataPacket(DataPacket content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    //PType = PacketType.DATAPACKET
                }
            };
            SendPacket(packet);
        }

        public void SendMachineTime(MachineTime content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    PType = PacketType.TimeSetting
                }
            };
            SendPacket(packet);
        }

        public void SendSamplingConfig(SamplingConfig content)
        {
            NetPacket packet = new NetPacket()
            {
                Data = content,
                PacketHead = new NetPacketHead()
                {
                    Version = 1,
                    PType = PacketType.SamplingPacket
                }
            };
            SendPacket(packet);
        }


        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="filePath"></param>
        public void SendFile(string filePath)
        {
            if (!File.Exists(filePath))
                return;
            FileStream fs = null;
            try
            {
                Byte[] filename = Encoding.Default.GetBytes(new FileInfo(filePath).Name);
                fs = new FileStream(filePath, FileMode.Open);
                Byte[] content = new Byte[sizeof(Int32) + filename.Length + fs.Length];//文件数据包包体大小=文件名长度(4字节)+文件名+文件内容
                Array.Copy(BitConverter.GetBytes(filename.Length), 0, content, 0, sizeof(Int32));//把"文件名长度(4字节)"放入数组
                Array.Copy(filename, 0, content, sizeof(Int32), filename.Length);//把"文件名字节数组"放入数组

                fs.Read(content, sizeof(Int32) + filename.Length, (Int32)fs.Length);//把"文件内容"放入数组

                //开始发包
                SendPacket
                (
                    new NetPacket()
                    {
                        Data = content,
                        PacketHead = new NetPacketHead()
                        {
                            Version = 1,
                            //PType = PacketType.BINARY,
                            //Len = content.Length
                        }
                    }
                );
            }
            finally
            {
                fs.Close();
            }
        }


        /// <summary>
        /// 序列化Helper
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public ISerialize Serializehelper<T>() where T : ISerialize
        {
            return Activator.CreateInstance<T>();
        }

        /// <summary>
        /// 缓冲区大小1024字节
        /// </summary>
        public const Int32 BUFFER_SIZE =65535;

        /// <summary>
        /// Udp数据报最大值
        /// </summary>
        protected const Int32 UDP_BUFFER_SIZE = 512;

        private ProtocolType _protocolType = ProtocolType.Tcp;
        
        /// <summary>
        /// 协议类型[默认为Tcp]
        /// </summary>
        public ProtocolType ProtocolType
        {
            set
            {
                _protocolType = value;
            }
        }

        /// <summary>
        /// 接收网络数据的缓冲区
        /// </summary>
        protected Byte[] _netDataBuffer = new Byte[BUFFER_SIZE * 4096];//之前缓冲区太小，发送速度过快，会阻塞，改成256无任何问题

        /// <summary>
        /// 缓冲区实际数据长度
        /// </summary>
        protected int _netDataOffset = 0;

        /// <summary>
        /// 网络流
        /// </summary>
        protected System.Net.Sockets.NetworkStream _netStream = null;

        /// <summary>
        /// 缓冲区
        /// </summary>
        protected Byte[] _tempBuffer = new Byte[BUFFER_SIZE];

        /// <summary>
        /// Udp套接字
        /// </summary>
        protected Socket _udpSocket;

        /// <summary>
        /// Tcp套接字
        /// </summary>
        protected Socket _tcpSocket;

        /// <summary>
        /// Udp发送的目标端点
        /// </summary>
        protected System.Net.EndPoint _udpRemoteEndPoint;

        public System.Net.EndPoint UdpRemoteEndPoint
        {
            get { return _udpRemoteEndPoint; }
            set { _udpRemoteEndPoint = value; }
        }

        /// <summary>
        /// 发包[Tcp发包和Udp发包行为略有不同,故转到子类实现]
        /// </summary>
        /// <param name="packet"></param>
        protected abstract void SendPacket(NetPacket packet);

        /// <summary>
        /// 缓冲区是否满足一个完整包头
        /// </summary>
        /// <returns></returns>
        protected Boolean IsFullNetPacketHead()
        {
            return _netDataOffset >= NetPacketHead.HEAD_SIZE;
        }

        /// <summary>
        /// 一个完整的网络封包的大小
        /// </summary>
        protected Int32 FullNetPacketSize
        {
            get
            {
                if (!IsFullNetPacketHead())
                    throw new Exception("由于没有缓冲区数据不足一个包头大小因此不能获得完整网络封包大小");
                return NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8);
            }

        }

        /// <summary>
        /// 缓冲区是否满足一个完整封包
        /// </summary>
        /// <returns></returns>
        protected Boolean IsFullNetPacket()
        {
            Console.WriteLine("接收长度:"+ _netDataOffset.ToString()+"实际长度:"+ (NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8)).ToString());
            return _netDataOffset >= NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8);
        }


        /// <summary>
        /// 从缓冲区提取一个包头,但并不从缓冲区删除该包头
        /// </summary>
        /// <returns></returns>
        protected NetPacketHead PeekNetPacket()
        {
            NetPacketHead packetHead = new NetPacketHead();
            packetHead.Version = BitConverter.ToInt32(_netDataBuffer, 0);//版本
            packetHead.PType = (PacketType)BitConverter.ToInt32(_netDataBuffer, 4);//封包类型
            packetHead.Len = BitConverter.ToInt32(_netDataBuffer, 8);
            return packetHead;
        }

        /// <summary>
        /// 从缓冲区提取一个网络包
        /// </summary>
        /// <returns></returns>
        protected NetPacket PickNetPacket()
        {

            #region【提取包头】
            NetPacketHead packetHead = PeekNetPacket();
            #endregion

            #region【提取包体】
            NetPacket packet = new NetPacket();
            packet.PacketHead = packetHead;
            Byte[] buffer = new Byte[packetHead.Len];
            Array.Copy(_netDataBuffer, NetPacketHead.HEAD_SIZE, buffer, 0, packetHead.Len);
            switch (packetHead.PType)
            {
                case PacketType.STRING:
                    packet.Data = Serializehelper<StringSerializeHelper>().DeSerialize<string>(buffer);
                    break;
                case PacketType.ACQParametersConfig:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<ACQParametersConfig>(buffer);
                    break;
                case PacketType.AccelerationPacket:

                    switch (MdlClass_TCP.LineNum)
                    {
                        case 256:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_256>(buffer);
                            break;
                        case 512:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_512>(buffer);
                            break;
                        case 1024:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_1024>(buffer);
                            break;
                        case 2048:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_2048>(buffer);
                            break;
                        case 4096:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_4096>(buffer);
                            break;
                        case 8192:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_8192>(buffer);
                            break;
                        case 16384:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_16384>(buffer);
                            break;
                        case 32768:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_32768>(buffer);
                            break;
                        case 65536:
                            packet.Data = Serializehelper<StructHelper>().DeSerialize<Acceleration_65536>(buffer);
                            break;

                    }

                    break;
                case PacketType.DisplacementPacket:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<DisplacementData>(buffer);
                    break;
                case PacketType.SlowSignalPacket:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<SlowSignal>(buffer);
                    break;
                case PacketType.SpeedPacket:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<SpeedData>(buffer);
                    break;
                case PacketType.SamplingPacket:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<SamplingConfig>(buffer);
                    break;
                case PacketType.TimeSetting:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<MachineTime>(buffer);
                    break;
                case PacketType.TimeUpload:
                    packet.Data = Serializehelper<StructHelper>().DeSerialize<MachineTime>(buffer);
                    break;
                default:
                    break;
            }
            #endregion

            #region【从缓冲区删除该数据封包】
            Array.Copy(_netDataBuffer, NetPacketHead.HEAD_SIZE + packetHead.Len, _netDataBuffer, 0, _netDataOffset - (NetPacketHead.HEAD_SIZE + packetHead.Len));
            _netDataOffset -= (NetPacketHead.HEAD_SIZE + packetHead.Len);//缓冲区实际数据长度减去一个完整封包长度
            #endregion

            return packet;
        }
    }
}
